#pragma once

#include <spdlog/details/file_helper.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/synchronous_factory.h>
#include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/base_sink.h>

#include <chrono>
#include <functional>
#include <mutex>
#include <string>
#include <thread>

namespace spdlog {
namespace sinks {

struct PlainMsg;
namespace ThreadLocalLogDeal {
struct SpdlogMsgWrapper;
struct AlignBuf;
}  // namespace ThreadLocalLogDeal
class SpinLockLimitTimeSink : public sink {
 public:
  typedef std::function<std::string()> RotatingFunction;
  SpinLockLimitTimeSink(filename_t base_filename, std::size_t max_size,
                        std::size_t max_files, RotatingFunction func,
                        bool rotate_on_open = false,
                        const file_event_handlers &event_handlers = {});
  virtual ~SpinLockLimitTimeSink();
  void log(const details::log_msg &msg) override { sink_it_(msg); }
  void set_pattern(const std::string &pattern) override {
    // std::lock_guard<std::mutex> lock(mutex_);
    set_formatter(details::make_unique<spdlog::pattern_formatter>(pattern));
  }

  void set_formatter(
      std::unique_ptr<spdlog::formatter> sink_formatter) override {
    formatter_ = std::move(sink_formatter);
  }

  void flush() {}

  void Rotate();
  static bool BufSizeIsOk(
      const std::unique_ptr<ThreadLocalLogDeal::AlignBuf> &);

 protected:
  void sink_it_(const details::log_msg &msg);
  void flush_();

 private:
  void ThreadFunc();
  void StartNewThread();
  void WriteBuffer(const std::unique_ptr<ThreadLocalLogDeal::AlignBuf> &msg);
  // std::unique_ptr<std::vector<ThreadLocalLogDeal::SpdlogMsgWrapper>>
  //     flushing_buf_, active_buf_;

  std::unique_ptr<std::thread> write_thread_;
  std::atomic<bool> need_end_{false};
  filename_t base_filename_;
  std::size_t max_size_;
  std::size_t max_files_;
  std::size_t current_size_;
  details::file_helper file_helper_;
  std::atomic_flag flag_ = ATOMIC_FLAG_INIT;
  std::unique_ptr<spdlog::formatter> formatter_;
  std::mutex mutex_;
  int file_fd_;
  std::unique_ptr<ThreadLocalLogDeal::AlignBuf> flushing_buf_, active_buf_;

  RotatingFunction rotate_func_;
  bool rotate_on_open_;
  bool last_write_is_ok_;
};
}  // namespace sinks
}  // namespace spdlog
